package com.hy.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hy.Result.ResponseResult;
import com.hy.appMedicine.dto.MedicineQueryDTO;
import com.hy.mapper.*;
import com.hy.medicine.MedCommonCategory;
import com.hy.medicine.MedicineBasicInfo;
import com.hy.medicine.MedicineStock;
import com.hy.medicine.MedicineStockRecord;
import com.hy.medicine.vo.MedicineEvaluationVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.List;


/**
 * @author 陌寒    Lenovo
 * @date 2025/3/13下午6:37
 * @description 类描述
 */
@Slf4j
@Service
@Transactional(readOnly = true)
public class MedicineServiceImpl implements MedicineService{

    @Autowired
    private MedicineBasicInfoMapper medicineBasicInfoMapper;

    @Autowired
    private MedicineStockMapper medicineStockMapper;

    @Autowired
    private MedicineStockRecordMapper medicineStockRecordMapper;

    @Autowired
    private MedicineEvaluationMapper medicineEvaluationMapper;

    @Autowired
    private MedCommonCategoryMapper medCommonCategoryMapper;

    /**
     * 获取药品分类列表。
     *
     * 该方法从数据库中查询所有药品分类信息，并将结果封装在ResponseResult对象中返回。
     * 如果在查询过程中发生任何异常，将捕获该异常并记录错误日志，随后返回一个包含错误信息的ResponseResult对象。
     *
     * @return ResponseResult 若查询成功，返回包含药品分类列表的成功响应结果；若查询失败，返回包含错误码和错误信息的响应结果
     */
    @Override
    public ResponseResult getCategories() {
        try {
            List<MedCommonCategory> categories = medCommonCategoryMapper.selectList(null);
            return ResponseResult.okResult(categories);
        } catch (Exception e) {
            log.error("获取药品分类失败", e);
            return ResponseResult.errorResult(500, "获取药品分类失败");
        }
    }

    /**
     * 根据查询条件获取药品列表。
     *
     * 该方法根据传入的MedicineQueryDTO对象中的查询条件，从数据库中查询药品列表，并将结果封装在ResponseResult对象中返回。
     * 如果在查询过程中发生任何异常，将捕获该异常并记录错误日志，随后返回一个包含错误信息的ResponseResult对象。
     *
     * @param queryDTO 包含查询条件的MedicineQueryDTO对象
     * @return ResponseResult 若查询成功，返回包含药品列表的成功响应结果；若查询失败，返回包含错误码和错误信息的响应结果
     */
    @Override
    public ResponseResult getMedicineList(MedicineQueryDTO queryDTO) {
        try {
            // 显式指定Page的泛型类型为MedicineBasicInfo
            Page<MedicineBasicInfo> page = new Page<MedicineBasicInfo>(
                    queryDTO.getPageNum() != null ? queryDTO.getPageNum() : 1,
                    queryDTO.getPageSize() != null ? queryDTO.getPageSize() : 10
            );

            // 构建查询条件
            LambdaQueryWrapper<MedicineBasicInfo> wrapper = new LambdaQueryWrapper<>();

            // 按分类查询
            if (StringUtils.hasText(queryDTO.getCategoryId())) {
                wrapper.eq(MedicineBasicInfo::getCommonCategoryId, queryDTO.getCategoryId());
            }

            // 关键词搜索
            if (StringUtils.hasText(queryDTO.getKeyword())) {
                wrapper.like(MedicineBasicInfo::getMedicineName, queryDTO.getKeyword())
                        .or()
                        .like(MedicineBasicInfo::getManufacturer, queryDTO.getKeyword());
            }

            // 执行查询
            IPage<MedicineBasicInfo> result = medicineBasicInfoMapper.selectPage(page, wrapper);

            // 查询分类名称
            if (result.getRecords() != null && !result.getRecords().isEmpty()) {
                for (MedicineBasicInfo medicine : result.getRecords()) {
                    // 设置分类名称
                    if (StringUtils.hasText(medicine.getCommonCategoryId())) {
                        MedCommonCategory category = medCommonCategoryMapper.selectById(medicine.getCommonCategoryId());
                        if (category != null) {
                            medicine.setCommonCategoryName(category.getName());
                        }
                    }
                }
            }

            return ResponseResult.okResult(result);
        } catch (Exception e) {
            log.error("获取药品列表失败", e);
            return ResponseResult.errorResult(500, "获取药品列表失败");
        }
    }

    /**
     * 获取指定ID的药品详细信息。
     *
     * 该方法根据传入的药品ID，从数据库中查询药品的详细信息，并将结果封装在ResponseResult对象中返回。
     * 如果药品不存在，将返回一个包含错误信息的ResponseResult对象。
     * 查询成功后，还会查询该药品的库存信息，并将其设置到药品详细信息对象中。
     *
     * @param medicineId 药品的唯一标识ID
     * @return ResponseResult 若查询成功，返回包含药品详细信息的成功响应结果；若药品不存在，返回包含错误码和错误信息的响应结果
     */
    @Override
    public ResponseResult getMedicineDetail(Integer medicineId) {
        // 查询药品详情
        MedicineBasicInfo medicine = medicineBasicInfoMapper.selectMedicineDetailWithCategory(medicineId);
        if (medicine == null) {
            return ResponseResult.errorResult(500, "药品不存在");
        }

        // 查询库存信息
        MedicineStock stock = medicineStockMapper.selectOne(
                new LambdaQueryWrapper<MedicineStock>()
                        .eq(MedicineStock::getMedicineId, medicineId)
        );

        if (stock != null) {
            medicine.setMinStock(stock.getStockQuantity());
        }

        return ResponseResult.okResult(medicine);
    }

    /**
     * 获取指定ID的药品库存信息。
     *
     * 该方法根据传入的药品ID，从数据库中查询该药品的库存信息，并将结果封装在ResponseResult对象中返回。
     * 如果药品不存在对应的库存信息，返回的库存对象将为null。
     *
     * @param medicineId 药品的唯一标识ID
     * @return ResponseResult 包含药品库存信息的成功响应结果；若药品ID无效或库存信息不存在，库存对象为null
     */
    @Override
    public ResponseResult getMedicineStock(Integer medicineId) {
        MedicineStock stock = medicineStockMapper.selectOne(
                new LambdaQueryWrapper<MedicineStock>()
                        .eq(MedicineStock::getMedicineId, medicineId)
        );
        return ResponseResult.okResult(stock);
    }

    /**
     * 更新指定药品的库存信息。
     *
     * 该方法根据传入的库存变动记录，更新相应药品的库存数量。如果药品库存记录不存在，或者更新后的库存数量小于0，
     * 则返回错误响应。更新库存后，还会保存库存变动记录。
     *
     * @param record 医药库存变动记录对象，包含药品ID、变动数量、操作类型等信息
     * @return ResponseResult 包含更新结果的成功响应；若更新失败，返回包含错误信息的响应
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult updateMedicineStock(MedicineStockRecord record) {
        try {
            // 查询当前库存
            MedicineStock stock = medicineStockMapper.selectOne(
                    new LambdaQueryWrapper<MedicineStock>()
                            .eq(MedicineStock::getMedicineId, record.getMedicineId())
            );
            if (stock == null) {
                return ResponseResult.errorResult(500, "药品库存记录不存在");
            }

            // 更新库存
            Integer newQuantity = stock.getStockQuantity() + record.getChangeQuantity();
            if (newQuantity < 0) {
                return ResponseResult.errorResult(500, "库存不足");
            }

            stock.setStockQuantity(newQuantity);
            if (record.getChangeQuantity() < 0) {
                stock.setOutDate(new Date());
            }
            medicineStockMapper.updateById(stock);

            // 保存变动记录
            record.setBeforeQuantity(stock.getStockQuantity());
            record.setAfterQuantity(newQuantity);
            record.setOperateTime(new Date());
            medicineStockRecordMapper.insert(record);

            return ResponseResult.okResult("库存更新成功");
        } catch (Exception e) {
            return ResponseResult.errorResult(500, "库存更新失败：" + e.getMessage());
        }
    }

    /**
     * 获取指定ID的药品评价列表。
     *
     * 该方法根据传入的药品ID，从数据库中查询该药品的所有评价记录，并将结果封装在ResponseResult对象中返回。
     * 每个评价记录包括用户的详细信息。
     *
     * @param medicineId 药品的唯一标识ID
     * @return ResponseResult 包含药品评价列表的成功响应结果
     */
    @Override
    public ResponseResult getMedicineEvaluations(Integer medicineId) {
        List<MedicineEvaluationVO> evaluations = medicineEvaluationMapper.selectEvaluationsWithUser(medicineId);
        return ResponseResult.okResult(evaluations);
    }




    @Override
    @Transactional
    public boolean decreaseStock(Integer medicineId, Integer quantity) {
        // 先检查库存是否充足
        if (!checkStock(medicineId, quantity)) {
            return false;
        }

        // 减少库存
        int rows = medicineBasicInfoMapper.updateStock(medicineId, quantity);
        return rows > 0;
    }

    @Override
    public boolean checkStock(Integer medicineId, Integer quantity) {
        int count = medicineBasicInfoMapper.checkStock(medicineId, quantity);
        return count > 0;
    }
}
